<template>
  <ul class="tree-comm" ref="tree">
    <li v-for="(item, index) in treeData" :key="index" :active="item.active">
      <div @click="toggle(item, index, 1)" :style="getChild(1,item, level)"
        @dragenter="dragGet($event, 1)" @dragover="dragGet($event, 2)"
        @dragleave="dragGet($event, 3)" @drop="dragGet($event, 4, item)"
        :class="{line:line&&level>1}">
        <i class="tree-icon" :open="item.show" @click.stop="toggle(item, index, 2)"
          v-if="getChild(2,item)" :style="iconStyle"></i>
        <slot name="icon"><i class="tree-icon-file" v-if="iconDef"></i></slot>
        <slot :row="item" :$index="index">{{ item[option.label] }}</slot>
        <slot name="append" :row="item" :$index="index"></slot>
      </div>
      <el-collapse-transition>
        <c-tree v-show="item.show" v-if="getChild(3,item)" :iScale="iScale"
          :level="level+1" :treeData="item[child]" :option="option" :iTop="iTop"
          :isDrag="isDrag" :iconDef="iconDef" :isControlFloder="isControlFloder"
          :accordion="accordion" :line="line"
          @dragHandle="$emit('dragHandle',arguments)" :isLeaf="isLeaf" :lazy="lazy"
          @clearActive="clearActiveEven" @node-click="nodeClick">
          <template #icon><slot name="icon"></slot></template>
          <template #default="{row,$index}"><slot :row="row" :$index="$index"></slot></template>
          <template #append="{row,$index}"><slot name="append" :row="row" :$index="$index"></slot></template>
        </c-tree>
      </el-collapse-transition>
    </li>
  </ul>
</template>

<script>

import ElCollapseTransition from 'element-ui/lib/transitions/collapse-transition'
export default {
  name: 'cTree', // 组件递归必须有name属性 不然无法递归
  props: {
    treeData: {
      type: Array, // 校验父组件传过来的数据
      default() { return [] }
    },
    option: { // 配置label children
      type: Object,
      default() {
        return {
          label: 'name', children: 'children',
          offActive: false, isLeaf: 'leaf'
        }
      }
    },
    accordion: Boolean, // 是否启动手风琴-模式
    lazy: Boolean, // 是否启动-懒加载
    isLeaf: String, // 懒加载字段 - 优先级大于option.isLeaf
    level: { // 目录级别
      type: Number,
      default: 1
    },
    isControlFloder: { // 是否控制目录
      type: Boolean,
      default: true
    },
    isDrag: { // 是否启用-拖拽监听
      type: Boolean,
      default: false
    },
    iconDef: { // 默认icon
      type: Boolean,
      default: false
    },
    iScale: { // icon 放大倍数
      type: Number,
      default: 1.5
    },
    iTop: String, // icon 偏移高度
    line: Boolean // 是否加虚线-对应
  },
  data() {
    return {
      // 拖拽-样式
      dragStyle: {}, iconTop: 0
    }
  },
  computed: {
    child() { // 子-key
      return this.option.children
    },
    iconStyle() {
      let top = ''
      if (this.iTop) {
        top = `top:${this.iTop};`
      }
      return `left: ${(this.level - 1) * 20}px;${top}scale(${this.iScale});`
    }
  },
  components: { ElCollapseTransition },
  created() {
  },
  mounted() {
  },
  methods: {
    // 点击目录1 点击箭头2
    toggle(item, ind, type, parentList) {
      const pList = parentList || this.treeData
      switch (type) {
        case 1: // 点击目录
          if (!item.active) {
            this.clearActiveEven() // 清除已有的
          }
          this.$nextTick(() => {
            if (!(item.active && !this.option.offActive)) {
              item.active = !item.active
              this.$set(pList, ind, item)
            }
            // 模拟-点击箭头
            if (this.isControlFloder) {
              if (parentList) {
                this.toggle(item, ind, 2, parentList)
              } else {
                this.toggle(item, ind, 2)
              }
            }
            this.$emit('node-click', {
              row: item, parent: pList, type: 'node', index: ind
            })
          })
          break
        case 2: // 点击箭头
          if (item[this.child] && item[this.child].length) {
            if (this.accordion) { // 手风琴模式
              this.closeChild(pList)
            }
            item.show = !item.show
            this.$set(pList, ind, item)
          }
          this.$emit('node-click', {
            row: item, parent: pList, type: 'icon', index: ind
          })
          break
      }
    },
    // 手风琴-只能有一个打开
    closeChild(pList) {
      if (pList) {
        const showObj = pList.find(o => o.show)
        this.$set(showObj, 'show', false) // 更新视图-关闭
      }
    },
    // 清除事件
    clearActiveEven() {
      if (this.level != 1) { // 子
        this.$emit('clearActive')
      } else {
        this.clearActive(this.treeData)
      }
    },
    // 清除选中项
    clearActive(list) {
      list.forEach((o, i) => {
        if (o.active) {
          o.active = false
          this.$set(list, i, o) // 更新视图
          return
        }
        if (o[this.child] && o[this.child].length) {
          this.clearActive(o[this.child])
        }
      })
    },
    // 接收子组件-事件向上传递
    nodeClick(item) {
      this.$emit('node-click', item)
    },
    // 拖拽-进入
    dragGet(e, type, row) {
      if (!this.isDrag) { // 禁止监听-拖拽处理
        return false
      }
      const style = e.target.style
      switch (type) {
        case 1: // 拖-进入
          this.dragStyle.border = style.border
          this.dragStyle.background = style.background
          e.target.style.border = '1px dashed #9bc18a'
          e.target.style.background = '#e3ffdd'
          break
        case 2: // 拖-持续
          e.preventDefault()
          break
        case 3: // 拖-离开
          e.target.style.border = this.dragStyle.border
          e.target.style.background = this.dragStyle.background
          break
        default: { // 拖-放下
          e.target.style.border = this.dragStyle.border
          e.target.style.background = this.dragStyle.background
          const json = e.dataTransfer.getData('data')
          const table = json ? JSON.parse(json) || '' : ''
          // 事件传递-出去
          this.$emit('dragHandle', row, table)
          e.preventDefault() // 阻止默认事件
          e.stopPropagation() // 阻止冒泡-事件中止
        }
      }
    },
    // Child - style
    getChild(type, item) {
      const { child } = this
      const bool = item[child] && item[child].length
      switch (type) {
        case 1: { // css
          const left = (this.level - 1) * 20 - 15
          const width = this.getChild(2, item) ? 15 : 25
          const leftStr = this.line ? `--line-left:${left}px;--line-width:${width}px;` : ''
          return `${leftStr}padding-left: ${this.level * 20}px;`
        }
        case 2: { // icon
          const leaf = this.isLeaf || this.option.isLeaf
          // 懒加载
          return this.lazy ? !!item[leaf] : bool
        }
        case 3: // child
          return bool
      }
    }
  }
}
</script>
<style lang="scss" scoped>
$file-img: '';
.tree-comm{
  list-style-type: none;
  padding: 0;
  color: #1C4257;
  font-size: 14px;
  li{
    position: relative;
    &:last-child .line::before{
      height: calc(100% - 10px);
    }
    div{
      padding: 5px 20px;
      display: block;
      &:not(.line):hover{ // 移入
        border: 1px solid #9bc18a;
        border-radius: 5px;
        background: #dedede;
        cursor: pointer;
      }
      &.line{ // 线条
        position: relative;
        &:hover{
          border-radius: 5px;
          background: #e6e6e6;
          cursor: pointer;
        }
        &::before{
          content: '';
          height: 100%;
          width: 1px;
          top: -5px;
          left: var(--line-left);
          position: absolute;
          border-left: 1px dashed #4386c6;
        }
        &::after{
          border-top: 1px dashed #4386c6;
          height: 1px;
          top: 10px;
          left: var(--line-left);
          width: var(--line-width);
          position: absolute;
          content: '';
        }
      }
    }
    &[active]{ // 选中
      &>div{
        border: 1px solid #dcdcdc;
        border-radius: 5px;
        background: #d0d0d0;
      }
    }
    // icon-file
    .tree-icon-file{
      width: 24px;
      height: 24px;
      line-height: 24px;
      transform: scale(1.5);
      display: inline-block;
      vertical-align: top;
      background-image: url($file-img);
      background-position: -260px -4px;
    }
    // icon
    .tree-icon{
      position: absolute;
      // left: 0px;
      top: 0;
      width: 24px;
      height: 24px;
      line-height: 24px;
      transform: scale(1.8);
      background-image: url($file-img);
      background-position: -5px -4px;
      &[open]{
        cursor: default;
        background-position: -38px -4px;
      }
      &:not([open]):hover{
        cursor: copy;
        background-position: -69px -67px;
      }
    }
  }
}
</style>
